package kr.ac.ssu.ailab.Model.Data;

import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.net.URL;

import kr.ac.ssu.ailab.Control.CellControl;
import kr.ac.ssu.ailab.Control.EventListener;
import kr.ac.ssu.ailab.Control.MapControl;
import kr.ac.ssu.ailab.Control.NewHeuristicPathFinding;
import kr.ac.ssu.ailab.View.SeqTest;

/**
 * 셀의 모든집함을 구성하는 Map 클래스
 * 
 * @author Neil
 */

public class Map
{

	/* Cell size */
	// private int cellSizeX;
	// private int cellSizeY;
	/* number of cells x, y */
	private int numX;
	private int numY;
	private Cell[][] cell;
	private static Cell startCell;
	private static Cell FinishCell;
	private Point clickedPoint;

	/**
	 * 생성자
	 * @param numX
	 * @param numY
	 */
	public Map(int numX, int numY)
	{
		this.numX = numX;
		this.numY = numY;

		cell = new Cell[numX][numY];

		for (int i = 0; i < numY; i++)
		{
			for (int j = 0; j < numX; j++)
			{
				cell[j][i] = new Cell(new Point(j, i));
				cell[j][i].setPosition(j, i);
			}
		}
	}

	/**
	 * 장애물을 설정하는 메소드
	 * @param x
	 * @param y
	 * @param mode
	 */
	public void setObstacle(int x, int y, int mode)
	{

		switch (mode)
			{
			case MapControl.SET_OBSTACLES:
				Point p = new Point(cell[x][y].getPosition().x,cell[x][y].getPosition().y);
				MapControl.addObstacleList(p);
				if (cell[x][y].getType() == (CellControl.START_CELL))
				{
					System.out.println("unable to set Obstacles on Start Cell");
					break;
				}
				else if (cell[x][y].getType() == (CellControl.FINISH_CELL))
				{
					System.out.println("unable to set Obstacles on Finish Cell");
					break;
				}
				else
				{
					CellControl.setObstacleCell(cell[x][y], CellControl.OBSTACLE,
							CellControl.OBSTACLE_COST);
					System.out.println("Impossible Obstacle Cell : " + cell[x][y]);
					break;
				}
			case MapControl.SET_HARD:
				CellControl.setCellType(cell[x][y], CellControl.HARD, CellControl.HARD_COST);
				System.out.println("Hard Cell : " + cell[x][y]);
				break;
			case MapControl.SET_NORMAL:
				p = new Point(cell[x][y].getPosition().x,cell[x][y].getPosition().y);
				MapControl.removeObstacleList(p);
				CellControl.setCellType(cell[x][y], CellControl.NORMAL, CellControl.NORMAL_COST);
				System.out.println("Normal Cell erased: " + cell[x][y]);
				break;
			}
	}

	/**
	 * 적을 설정하는 메소드
	 * @param x
	 * @param y
	 */
	public void setThreatn(int x, int y)
	{

		int range = SeqTest.mapControl.getRange();
		int startX = x - range + 1;
		int startY = y - range + 1;
		int endX = x + range;
		int endY = y + range;
		int cost = CellControl.THREATEN_AREA_COST;

		if (startX < 0)
		{
			startX = 0;
		}
		if (startY < 0)
		{
			startY = 0;
		}
		if (endX > numX)
		{
			endX = numX;
		}
		if (endY > numY)
		{
			endY = numY;
		}

		for (int i = startX; i < endX; i++)
			for (int j = startY; j < endY; j++)
			{
				if (!cell[i][j].isObstacle() && cell[i][j].getType() != CellControl.START_CELL)
				{
					if (SeqTest.mapControl.getLevel() >= 2)
					{
						if (NewHeuristicPathFinding.getGoalList().contains(cell[i][j]))
						{
							NewHeuristicPathFinding.getGoalList().remove(cell[i][j]);
						}
						if (NewHeuristicPathFinding.getPathList().contains(cell[i][j]))
						{
							NewHeuristicPathFinding.getPathList().remove(cell[i][j]);
						}
					}

					if (cell[i][j].getType() == CellControl.THREATEN_AREA)
					{
						double temp = cell[i][j].getWeight();

						int tempAlpha = cell[i][j].getThreatenLevel();
						if (tempAlpha > 155)
							tempAlpha = 155;

						if (Point.distance(i, j, x, y) > 2 * Point.distance(x, y, startX, startY) / 3)
						{
							CellControl.setCellType(cell[i][j], CellControl.THREATEN_AREA,
									(CellControl.THREATEN_AREA_COST) / 3 + temp);
							cell[i][j].setThreatenLevel(30 + tempAlpha);
						}
						else if (Point.distance(i, j, x, y) > Point.distance(x, y, startX, startY) / 3)
						{
							CellControl.setCellType(cell[i][j], CellControl.THREATEN_AREA, 2
									* (CellControl.THREATEN_AREA_COST) / 3 + temp);
							cell[i][j].setThreatenLevel(60 + tempAlpha);
						}
						else
						{
							CellControl.setCellType(cell[i][j], CellControl.THREATEN_AREA,
									CellControl.THREATEN_AREA_COST + temp);
							cell[i][j].setThreatenLevel(100 + tempAlpha);
						}
					}
					else if (Point.distance(i, j, x, y) > 2 * Point.distance(x, y, startX, startY) / 3)
					{
						CellControl.setCellType(cell[i][j], CellControl.THREATEN_AREA,
								(CellControl.THREATEN_AREA_COST) / 3);
						cell[i][j].setThreatenLevel(30);
					}
					else if (Point.distance(i, j, x, y) > Point.distance(x, y, startX, startY) / 3)
					{
						CellControl.setCellType(cell[i][j], CellControl.THREATEN_AREA,
								2 * (CellControl.THREATEN_AREA_COST) / 3);
						cell[i][j].setThreatenLevel(60);
					}
					else
					{
						CellControl.setCellType(cell[i][j], CellControl.THREATEN_AREA,
								CellControl.THREATEN_AREA_COST);
					}
				}
			}

	}

	/**
	 * 동적으로 움직이는 메소드
	 * @param eventPoint
	 */
	public void dynamicMethod(Point eventPoint)
	{
		if (MapControl.getIsSearch())
		{
			NewHeuristicPathFinding.change = true;
			//어떤 모드의 이벤트가 발생했는지..
			//MapControl.SET_Start 등등.... 
			int mode = MapControl.SET_FINISH;
						
			int px = eventPoint.x, py = eventPoint.y;
			EventListener eventListener = new EventListener(mode);

			int number = SeqTest.mapControl.getCellArray()[px][py].getIsIncludedIn();
			eventListener.setClusterNumber(number);

			synchronized (eventListener)
			{
				eventListener.run();
			}
		}
	}

	/**
	 * 목표점을 결정하는 메소드
	 * @param finishCell
	 */
	public void setFinishCell(Cell finishCell)
	{
		FinishCell = finishCell;

	}

	/**
	 * 목표점을 get 하는 메소드
	 * @return
	 */
	public static Cell getFinishCell()
	{
		return FinishCell;
	}

	/**
	 * 시작점을 결정하는 메소드
	 * @param startCell
	 */
	public void setStartCell(Cell startCell)
	{
		this.startCell = startCell;
	}

	/**
	 * 시작점을 get 하는 메소드
	 * @return
	 */
	public static Cell getStartCell()
	{
		return startCell;
	}

	/**
	 * 맵의 셀 전체를 얻는 메소드
	 * @return
	 */
	public Cell[][] getCellArray()
	{
		return cell;
	}

	/**
	 * 맵의 Y 크기를 결정하는 메소드
	 * @param numY
	 */
	public void setNumY(int numY)
	{
		this.numY = numY;
	}

	/**
	 * 맵의 Y 크기를 get 하는 메소드
	 * @return
	 */
	public int getNumY()
	{
		return numY;
	}

	/**
	 * 맵의 X 크기를 결정하는 메소드
	 * @param numX
	 */
	public void setNumX(int numX)
	{
		this.numX = numX;
	}

	/**
	 * 맵의 X 크기를 get 하는 메소드
	 * @return
	 */
	public int getNumX()
	{
		return numX;
	}

}
